package com.atguigu.gmall.activity.service.impl;

import com.atguigu.gmall.activity.model.SeckillGoods;
import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Stack;

/**
 * 业务实现类
 *
 * @author atguigu
 * @since 2023-09-22
 */
@Service
public class SeckillGoodsServiceImpl extends ServiceImpl<SeckillGoodsMapper, SeckillGoods> implements SeckillGoodsService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询秒杀表中当日满足秒杀商品列表；将秒杀商品放入缓存中：
     * * 分布式缓存Redis Hash(秒杀商品信息)  List（商品库存）
     * * 本地缓存？
     */
    @Override
    public void processSeckill2Cache() {
        //1.查询秒杀表中当日满足秒杀商品列表:当天、审核通过、库存数大于0
        LambdaQueryWrapper<SeckillGoods> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SeckillGoods::getStatus, "1");
        queryWrapper.gt(SeckillGoods::getStockCount, 0);
        String today = DateUtil.formatDate(new Date());
        queryWrapper.apply("DATE_FORMAT(start_time, '%Y-%m-%d') = '" + today + "'");
        List<SeckillGoods> seckillGoodsList = this.list(queryWrapper);

        //2.将商品信息跟商品库存放入分布式缓存Redis 以及 商品状态位放入本地缓存
        if (!CollectionUtils.isEmpty(seckillGoodsList)) {
            //2.1 创建当日秒杀商品hash结构绑定操作对象
            String seckillHashKey = RedisConst.SECKILL_GOODS;
            BoundHashOperations<String, String, SeckillGoods> seckillHashOps = redisTemplate.boundHashOps(seckillHashKey);

            //2.2 遍历秒杀商品集合 判断秒杀商品中是否包含该商品，如果包含不处理，反之放入缓存
            for (SeckillGoods seckillGoods : seckillGoodsList) {
                String hashKey = seckillGoods.getSkuId().toString();
                if (seckillHashOps.hasKey(hashKey)) {
                    continue;
                }
                seckillHashOps.put(hashKey, seckillGoods);

                //2.3 遍历过程中为当前商品生成库存List结构 放入元素（代表库存）
                String stockKey = RedisConst.SECKILL_STOCK_PREFIX + hashKey;
                BoundListOperations<String, String> stockListOps = redisTemplate.boundListOps(stockKey);
                Integer stockCount = seckillGoods.getStockCount();
                for (int i = 0; i < stockCount; i++) {
                    stockListOps.leftPush(hashKey);
                }
                //2.4 遍历过程中为当前商品“状态位”,将商品状态位发送到Redis话题，将来所有秒杀服务都会订阅Redis话题
                redisTemplate.convertAndSend("seckillpush", hashKey + ":1");
            }
        }
    }


    /**
     * 查询当日参与秒杀商品
     *
     * @return
     */
    @Override
    public List<SeckillGoods> getSeckillGoods() {
        BoundHashOperations<String, String, SeckillGoods> seckillHashOps = getSeckillGoodsHashOpes();
        return seckillHashOps.values();
    }


    /**
     * 返回操作秒杀商品对象
     *
     * @return
     */
    private BoundHashOperations<String, String, SeckillGoods> getSeckillGoodsHashOpes() {
        String seckillKey = RedisConst.SECKILL_GOODS;
        BoundHashOperations<String, String, SeckillGoods> seckillHashOps = redisTemplate.boundHashOps(seckillKey);
        return seckillHashOps;
    }

    /**
     * 查询秒杀商品详情
     *
     * @param skuId
     * @return
     */
    @Override
    public SeckillGoods getSecGoodsById(Long skuId) {
        BoundHashOperations<String, String, SeckillGoods> hashOpes = getSeckillGoodsHashOpes();
        String hashKey = skuId.toString();
        Boolean flag = hashOpes.hasKey(hashKey);
        if (flag) {
            return hashOpes.get(hashKey);
        }
        return null;
    }
}
